#include <sys/types.h>
#include <regex.h>
#include <time.h>
#include <stdarg.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "common.h"
#include "usermanager.h"
#include "part.h"
#include "upper.h"
#include "config.h"

#define ERROR_CODE_COUNT        200

pthread_mutex_t mutex_p = PTHREAD_MUTEX_INITIALIZER;

static error_code error_table[ERROR_CODE_COUNT] = {
    {NO_ERROR,"成功"},
    {UNKNOWN_ID,"不支持此id"},
//user    
    {ERROR_MORE_THAN_MAX_LONINS,"最多只能同时登录5名用户"},
    {ERROR_ALREADY_LOGGED,"此用户已经登录"},
    {ERROR_NO_FIND_USER,"用户名错误"},
    {ERROR_PASSWORD_WRONG,"密码错误"},
    {ERROR_USER_NO_LOGINED,"此用户没有登陆，不需要退出"},
    {ERROR_MAXED_USER_COUNT,"最多只能创建10个用户"},
    {ERROR_NO_AUTHORITY,"没有权限"},
    {ERROR_USERNAME_OVERLENGTH,"用户名过长，最多40字节"},
    {ERROR_PASSWORD_OVERLENGTH,"密码过长，最多20字节"},
    {ERROR_CANNOT_DELROOT,"root用户不能删除"},
    {ERROR_ONLY_CHANGESELF,"非root用户只能修改自己的密码"},

//upper
    {ERROR_PARSE_JSON,"json数据解析错误"},
    
//device
    {DEVICE_BUSY,"次模块正在进行其他通讯操作"},
    {COMM_TIMEOUT,"命令超时"},
    {MISSING_PARAM,"命令缺少参数"},
    {OXC_ATTN_NOT_ABS,"oxc有信道衰减不是用的绝对值"},
};

char* return_error_message(int error_code){
    int i;
    for(i=0;i<ERROR_CODE_COUNT;i++){
        if(error_code == error_table[i].id){
            return error_table[i].message;
        }
    }
    return "";
}

int convert_string2hex(unsigned char *in_data, int in_data_len, unsigned char *out_data, int *out_data_len){
    int i;
    int loop_count;
    int convert_point = 0;
    int mem_point = 0;
    unsigned char convert_result;
    unsigned char temp[3] = {0}; /* 为啥是3呢？ */
	
	/* 检查参数有效性 */
    if (in_data == NULL || in_data_len <= 0 || out_data == NULL || out_data_len == NULL || (in_data_len % 2) != 0) {
        printf("invalid parameters\n");
        return -1;
    }
	/* 判断是否超过16进制范围 0 ~ F */
    for (i = 0; i < in_data_len; i++) {
        if ((in_data[i] < '0') || (in_data[i] > 'f') || ((in_data[i] > '9') &&(in_data[i] < 'A'))) {
            printf("out of range\n");
            return -1;
        }
    }
    loop_count = in_data_len / 2;
    memset(out_data, 0x00, *out_data_len);
    *out_data_len = 0;

    for (i = 0; i < loop_count; i++) {
        memset(temp, 0x00, sizeof(temp));
        memcpy(temp, in_data + convert_point, 2);
        convert_point += 2;

        convert_result = strtoul(temp, NULL, 16);

        memcpy(out_data + mem_point, &convert_result, sizeof(unsigned char));
        mem_point += sizeof(unsigned char);
        *out_data_len += sizeof(unsigned char);
    }
    return 0;
}

int convert_hex2string(unsigned char *in_data, int in_data_len, unsigned char *out_data, int *out_data_len,int bit){
    uint8_t* p_8;
    uint16_t* p_16;
    uint32_t* p_32;
    char buf[8];
    int col = bit == 32?10:20;
    int i;
    if(bit == 8){
        p_8 = (uint8_t*)in_data;
        for(i=0;i<in_data_len;i++){
            sprintf(buf,"0x%02X ",p_8[i]);
            strcat(out_data,buf);
            if((i+1)%col == 0) strcat(out_data,"\r\n");
        }
    }
    if(bit == 16){
        p_16 = (uint16_t*)in_data;
        for(i=0;i<in_data_len/2;i++){
            sprintf(buf,"0x%04X ",p_16[i]);
            strcat(out_data,buf);
            if((i+1)%col == 0) strcat(out_data,"\r\n");
        }
    }
    if(bit == 32){
        p_32 = (uint32_t*)in_data;
        for(i=0;i<in_data_len/4;i++){
            sprintf(buf,"0x%08X ",p_32[i]);
            strcat(out_data,buf);
            if((i+1)%col == 0) strcat(out_data,"\r\n");
        }
    }
    if(i%col > 0) strcat(out_data,"\r\n");
    if(out_data_len) *out_data_len = strlen(out_data);
}

int find_key(char* pattern,char* source,int* begin,int* end,int is_array,int index){
    int i,z,cflags=REG_EXTENDED|REG_ICASE;
    char ebuf[256] = {0};
    regex_t reg;
    regmatch_t match[is_array+1];
    size_t nmatch = is_array+1;
    if(index > is_array) index = is_array;
    
    z = regcomp(&reg,pattern,cflags);
    if(z != REG_NOERROR){
        regerror(z,&reg,ebuf,sizeof(ebuf));
        printf_flag(print_debug,"regcomp error:%s pattern:%s' \n",ebuf,pattern);
        return 0;
    }

    z = regexec(&reg,source,nmatch,match,0);
    if(z != REG_NOERROR){
        regerror(z,&reg,ebuf,sizeof(ebuf));
        printf_flag(print_debug,"regexec error:%s : pattern '%s' \n",ebuf,pattern);
        regfree(&reg);
        return 0;
    }

    if(begin) *begin = match[index].rm_so;
    if(end) *end = match[index].rm_eo;    
    regfree(&reg);
    return 1;
}

int find_keys(char* pattern,char* source,size_t num,...){
    int z,cflags=REG_EXTENDED|REG_ICASE,i;
    char ebuf[256] = {0},*p;
    regex_t reg;
    regmatch_t match[num+1];
    va_list valist;
    
    z = regcomp(&reg,pattern,cflags);
    if(z != REG_NOERROR){
        regerror(z,&reg,ebuf,sizeof(ebuf));
        printf_flag(print_debug,"regcomp error:%s pattern:%s' \n",ebuf,pattern);
        return 0;
    }

    z = regexec(&reg,source,num+1,match,0);
    if(z != REG_NOERROR){
        regerror(z,&reg,ebuf,sizeof(ebuf));
        printf_flag(print_debug,"regexec error:%s : pattern '%s' \n",ebuf,pattern);
        regfree(&reg);
        return 0;
    }
    
    va_start(valist,num);
    for(i=0;i<num;i++){
        if(match[i+1].rm_so != -1){
            p = va_arg(valist,char*);
            strncpy(p,&source[match[i+1].rm_so],match[i+1].rm_eo - match[i+1].rm_so);
            p[match[i+1].rm_eo - match[i+1].rm_so] = 0;
        }
    }
    va_end(valist);
    return match[i].rm_eo;
}

char* time_to_string(uint32_t time,char* s_time,char* unit){    
    float f_time = 0.0f;
    if(strcmp(unit,"s") == 0){
        f_time = (float)time/CLOCKS_PER_SEC;
        sprintf(s_time,"%0.3fs",f_time);
    }
    else if(strcmp(unit,"ms") == 0){
        f_time = time*1000/CLOCKS_PER_SEC;
        sprintf(s_time,"%dms",f_time);
    }
    else if(strcmp(unit,"us") == 0){
        sprintf(s_time,"%dus",time);
    }
    else {
        sprintf(s_time,"0");
    }
    return s_time;
}

char* strmove(char* dst,char* src,int len){
    memmove(dst,src,len);
    dst[len] = 0;   
    return dst;
}


void htonls(int* data,int n){
    int i;
    for(i=0;i<n;i++){
        data[i] = htonl(data[i]);
    }
}

void printf_comm_flag(int dir,int flag,char* prefix,char* data,int len){
    char *msg;
    va_list arg;
    int index=0,s_len,size;
    char s_time[64] = {0};
    char* s_dir_send = "send to ";
    char* s_dir_recv = "recv from ";
    if((get_print_code() & (1<<flag)) == 0) return;
    get_exact_time(s_time);
    if(flag == print_opm){
        size = len*3+256;
        msg = malloc(size);
    }
    else{
        size = len + 256;
        msg = malloc(size);
    }
    if(msg == NULL) return;
    memset(msg,0,size);
    strcat(msg,"\r\n");
    strcat(msg,s_time);
    strcat(msg,"\r\n");
    strcat(msg,dir==0?s_dir_send:s_dir_recv);
    if(prefix){
        strcat(msg,prefix);        
    }     
    else{
        strcat(msg,"unknow");
    }
    strcat(msg,":\r\n");
    index = strlen(msg);
    if(flag == print_opm){
        convert_hex2string(data,len,msg+index,&s_len,32);
    }
    else{
        strcat(msg,data);
    }
    strcat(msg,"\r\n");
    printf(msg);
    free(msg);   
}

void printf_flag(int flag,char* fmt,...){
    char *msg;
    va_list arg;
    int ret;

    // pthread_mutex_lock(&mutex_p);
    if((get_print_code() & (1<<flag)) == 0) return;
    /* compute the length of the formatted message */
    va_start(arg, fmt);
    ret = vsnprintf(NULL, 0, fmt, arg);
    va_end(arg);

    /* allocated an array for the formatted message */
    if (ret < 0 || (msg = malloc(ret + 1)) == NULL) return;

    /* construct the formatted message */
    va_start(arg, fmt);
    ret = vsnprintf(msg, ret + 1, fmt, arg);
    va_end(arg);

    /* send the message using the write system call */
    printf(msg);
    free(msg);
    // pthread_mutex_unlock(&mutex_p);
}

void update_date(char* date){
    int fd,ret;
    struct rtc_time rtc_tm;
    char year[6]={0},month[6]={0},day[6]={0},hour[6]={0},minute[6]={0},second[6]={0};
    pthread_mutex_lock(&mutex_p);
    if(find_keys("^([1-9][0-9]{3})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) +(20|21|22|23|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])$",
                    date,6,year,month,day,hour,minute,second)){   
        rtc_tm.tm_year = strtol(year,NULL,10) - 1900;        
        rtc_tm.tm_mon = strtol(month,NULL,10) - 1;        
        rtc_tm.tm_mday = strtol(day,NULL,10);        
        rtc_tm.tm_hour = strtol(hour,NULL,10);        
        rtc_tm.tm_min = strtol(minute,NULL,10);        
        rtc_tm.tm_sec = strtol(second,NULL,10);        
        fd = open("/dev/rtc0",O_WRONLY);
        ret = ioctl(fd, RTC_SET_TIME, &rtc_tm);
        close(fd);
    }
    pthread_mutex_unlock(&mutex_p);
}

void get_date(char* date){
    int fd,ret;
    struct rtc_time rtc_tm;
    pthread_mutex_lock(&mutex_p);
    fd = open("/dev/rtc0",O_RDONLY);
    ret = ioctl(fd, RTC_RD_TIME, &rtc_tm);
    sprintf(date,"%d-%02d-%02d",rtc_tm.tm_year + 1900,rtc_tm.tm_mon + 1,rtc_tm.tm_mday);
    close(fd);
    pthread_mutex_unlock(&mutex_p);
}

void get_time(char* time){
    int fd,ret;
    struct rtc_time rtc_tm;
    pthread_mutex_lock(&mutex_p);
    fd = open("/dev/rtc0",O_RDONLY);
    ret = ioctl(fd, RTC_RD_TIME, &rtc_tm);
    sprintf(time,"%02d:%02d:%02d",rtc_tm.tm_hour,rtc_tm.tm_min,rtc_tm.tm_sec);
    close(fd);    
    pthread_mutex_unlock(&mutex_p);
}

void get_exact_time(char* time){
    int fd,ret;
    struct rtc_time rtc_tm;
    pthread_mutex_lock(&mutex_p);
    fd = open("/dev/rtc0",O_RDONLY);
    ret = ioctl(fd, RTC_RD_TIME, &rtc_tm);
    sprintf(time,"%d-%02d-%02d %02d:%02d:%02d",rtc_tm.tm_year + 1900,rtc_tm.tm_mon + 1,rtc_tm.tm_mday,
                                     rtc_tm.tm_hour,rtc_tm.tm_min,rtc_tm.tm_sec);
    
    close(fd);    
    pthread_mutex_unlock(&mutex_p);
}

#define INT     0
#define FLOAT   1

void array_to_string(void* array,int size,int bit,char* out,int type){
    int* p_i;
    float* p_f;
    int i;
    if(out == NULL) return;
    if(type == INT) {
        p_i = (int*)array;
        for(i=0;i<size;i++){
            sprintf(out+strlen(out),"%d,",p_i[i]);
        }        
    }
    else {
        p_f = (float*)array;
        for(i=0;i<size;i++){
            if(bit == 1){
                sprintf(out+strlen(out),"%0.1f,",p_f[i]);
            }
            else if(bit == 2){
                sprintf(out+strlen(out),"%0.2f,",p_f[i]);
            }
            else{
                sprintf(out+strlen(out),"%0.4f,",p_f[i]);
            }
        }        
    }
    out[strlen(out)-1] = 0;
}

void string_to_array(char* s_list,void* array,int* size,int type){
    int b,e,i=0,index=0,ret;
    char s_num[32];
    int i_num;
    float f_num;
    if(s_list == NULL) return;
    while(ret = find_keys("([0-9\\.-]+)",s_list+index,1,s_num)){        
        if(type == FLOAT){
            f_num = strtof(s_num,NULL);
            memcpy(array+i*sizeof(float),&f_num,sizeof(float));
        }
        else{
            i_num = strtol(s_num,NULL,10);
            memcpy(array+i*sizeof(int),&i_num,sizeof(int));
        }
        i++;   
        index += ret;     
    }
    if(size) *size = i;
}